using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using PortfolioAllocator.Optimization;
using ZedGraph;
using TALoaders;

namespace PortfolioAllocator.GUI
{
    public partial class AllocationResult : Form
    {
        #region Colors
        private static Color[] colorM = new Color[]{
                                            Color.AliceBlue,
                                            Color.Red,
                                            Color.Aqua,
                                            Color.Green,
                                            Color.Azure,
                                            Color.Purple,
                                            Color.Bisque,
                                            Color.Black,
                                            Color.BlanchedAlmond,
                                            Color.Blue,
                                            Color.BlueViolet,
                                            Color.Brown,
                                            Color.BurlyWood,
                                            Color.CadetBlue,
                                            Color.Chartreuse,
                                            Color.Chocolate,
                                            Color.Coral};
        #endregion
        public enum ResultType { Allocation, BackTest };

        public AllocationResult(DataTable optResult, ResultType rType)
        {
            InitializeComponent();

            // Initialize tabTable
            this.dgViewM.DataSource = optResult;
            // Format DataGridView Columns
            for (int ix = 0; ix < optResult.Columns.Count; ++ix)
            {
                DataGridViewColumn col = dgViewM.Columns[ix];
                if (optResult.Columns[ix].ExtendedProperties.ContainsKey(OptimizationRunner.FORMAT_EXT_PROPERTY))
                    col.DefaultCellStyle.Format = (string)optResult.Columns[ix].ExtendedProperties[OptimizationRunner.FORMAT_EXT_PROPERTY];
            }
            this.dgViewM.RowHeadersVisible = false;

            switch (rType)
            {
                case ResultType.Allocation:
                    this.createOptWeightsChart(this.zgControlWeightsM, optResult); // Chart: Weights
                    this.createRiskReturnChart(this.zgControlRiskRetsM, optResult); // Chart: Risk/Return
                    break;
                case ResultType.BackTest:
                    this.createWeightsDevelopmentChart(this.zgControlWeightsM, optResult);  // Chart: Weights
                    this.createCumulReturnChart(this.zgControlRiskRetsM, optResult);    // Chart: Cumulative Return
                    break;
                default:
                    throw new Exception("Unsupported ResultType: " + rType.ToString());
            }
        }

        private void createCumulReturnChart(ZedGraphControl zl, DataTable btResult)
        {
            this.tabRiskRetM.Text = "Chart: CumulReturn";
            // Preprocess data
            int nOfRows = btResult.Rows.Count;

            DataSourcePointList dspl = new DataSourcePointList();
            dspl.DataSource = btResult;
            dspl.XDataMember = OptimizationRunner.DATE_COL;
            dspl.YDataMember = OptimizationRunner.CUMUL_RET;
            dspl.ZDataMember = null;    // The Z data are not used
            // Create chart
            GraphPane myPane = zl.GraphPane;
            myPane.Title.Text = "Strategy Cumulative Return";
            myPane.XAxis.Title.Text = "Date";
            myPane.YAxis.Title.Text = "Cumulative Return";

            LineItem curve = myPane.AddCurve("Returns", dspl, Color.Red);
            curve.Symbol.Size = 1;
            myPane.Legend.IsVisible = false;    // // Hide the legend

            myPane.YAxis.Scale.Format = "P1";
            myPane.XAxis.Type = AxisType.Date;

            zl.AxisChange();    // Auto set the scale ranges
        }

        private void createWeightsDevelopmentChart(ZedGraphControl zl, DataTable btResult)
        {
            this.tabRiskRetM.Text = "Chart: Weights";
            // Preprocess data
            int nOfRows = btResult.Rows.Count;

            // Create chart
            GraphPane myPane = zl.GraphPane;
            myPane.Title.Text = "Portfolio Weights";
            myPane.XAxis.Title.Text = "Date";
            myPane.YAxis.Title.Text = "Weight";
            for (int i = 3; i < btResult.Columns.Count; ++i)    // Assuming that weights start form the 4th column!!!
            {
                DataSourcePointList dspl = new DataSourcePointList();
                dspl.DataSource = btResult;
                dspl.XDataMember = OptimizationRunner.DATE_COL;
                string ticker = btResult.Columns[i].ColumnName;
                dspl.YDataMember = ticker;
                dspl.ZDataMember = null;    // The Z data are not used

                LineItem curve = myPane.AddCurve(ticker, dspl, AllocationResult.colorM[i], SymbolType.None);
            }
            myPane.Legend.IsVisible = true;    // Hide the legend
            myPane.Legend.Position = LegendPos.Right;
            myPane.YAxis.Scale.Format = "P0";
            myPane.YAxis.Scale.Min = 0;
            myPane.XAxis.Type = AxisType.Date;

            zl.AxisChange();    // Auto set the scale ranges
        }

        private void createRiskReturnChart(ZedGraphControl zl, DataTable optResult)
        {
            // Preprocess data
            int nOfRows = optResult.Rows.Count;

            DataSourcePointList dspl = new DataSourcePointList();
            dspl.DataSource = optResult;
            dspl.XDataMember = OptimizationRunner.VOL_COL;
            dspl.YDataMember = OptimizationRunner.EXP_R_COL;
            dspl.ZDataMember = null;    // The Z data are not used
            // Create chart
            GraphPane myPane = zl.GraphPane;
            myPane.Title.Text = "Risk/Return";
            myPane.XAxis.Title.Text = "Volatility";
            myPane.YAxis.Title.Text = "Return";

            LineItem curve = myPane.AddCurve("Returns", dspl, Color.Red);

            curve.Line.IsVisible = false;     // Turn off the line so it's a scatter plot
            myPane.Legend.IsVisible = false;    // // Hide the legend

            double offset = 0.005;
            // Iterate over points and add ticker
            for (int i = 0; i < nOfRows; ++i)
            {
                PointPair pt = curve.Points[i]; // Get the pointpair

                string ticker = (string)optResult.Rows[i][OptimizationRunner.TICKER_COL];
                TextObj text = new TextObj(ticker, pt.X, pt.Y + offset, CoordType.AxisXYScale, AlignH.Left, AlignV.Center);
                text.ZOrder = ZOrder.A_InFront;
                // Hide the border and the fill
                text.FontSpec.Border.IsVisible = false;
                text.FontSpec.Fill.IsVisible = false;
                // Rotate the text to 45 degrees
                text.FontSpec.Angle = 45;
                myPane.GraphObjList.Add(text);
            }

            myPane.YAxis.Scale.Format = "P0";
            myPane.XAxis.Scale.Format = "P0";
            zl.AxisChange();    // Auto set the scale ranges
        }

        /// <summary>Create bar-chart with Min Variance and Kelly portfolio weights</summary>
        /// <param name="zl">ZedGraph control to create Pane</param>
        /// <param name="optResult">DataTAble with weights and tickers</param>
        private void createOptWeightsChart(ZedGraphControl zl, DataTable optResult)
        {
            // Preprocess data
            int nOfInstr = optResult.Rows.Count - 2;    // The last 2 rows corespond to Kely and MinVar portfolios
            PointPairList minVarList = new PointPairList();
            PointPairList kellyList = new PointPairList();
            string[] tickers = new string[nOfInstr];
            for (int i = 0; i < nOfInstr; ++i)
            {
                double wMinVar = (double)optResult.Rows[i][OptimizationRunner.MIN_VAR_W_COL];
                double wKelly = (double)optResult.Rows[i][OptimizationRunner.KELLY_W_COL];
                minVarList.Add(i, wMinVar);
                kellyList.Add(i, wKelly);
                tickers[i] = (string)optResult.Rows[i][OptimizationRunner.TICKER_COL];
            }
            // Show Bar-chart
            GraphPane myPane = zl.GraphPane;
            myPane.Title.Text = "Optimal Portfolio Composition";
            myPane.XAxis.Title.Text = "Ticker";
            myPane.YAxis.Title.Text = "Weight";

            BarItem minVarCurve = myPane.AddBar(OptimizationRunner.MIN_VAR_W_COL, minVarList, Color.Red);
            BarItem kellyCurve = myPane.AddBar(OptimizationRunner.KELLY_W_COL, kellyList, Color.Blue);

            myPane.XAxis.MajorTic.IsBetweenLabels = true; // Draw the X tics between the labels instead of at the labels
            myPane.XAxis.Scale.TextLabels = tickers;    // Set the XAxis labels
            myPane.XAxis.Type = AxisType.Text;          // Set the XAxis to Text type
            myPane.XAxis.Scale.FontSpec.Angle = 65;     // Tilt the x axis labels to an angle of 65 degrees

            myPane.YAxis.Scale.Format = "P0";
            myPane.YAxis.Scale.Min = 0;
            zl.AxisChange();

            // Bar Labels
            myPane.YAxis.Scale.Max += myPane.YAxis.Scale.MajorStep; // expand the range of the Y axis slightly to accommodate the labels
            BarItem.CreateBarLabels(myPane, false, "P1"); // Create TextObj's to provide labels for each bar
        }

        private void btSaveM_Click(object sender, EventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.DefaultExt = ".csv";
            dlg.Filter = "Result files (*.csv)|*.csv";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                DataTable dTable = (DataTable)this.dgViewM.DataSource;
                string fileName = dlg.FileName;
                Utilities.saveDataTableToCSV(fileName, dTable);
            }

        }
    }
}